/**
 * 系统时钟驱动
 * Copyright (c) 2021 深圳市智辰科技有限公司
 * All rights reserved.
 */

#include "driver_plf.h"
#include "driver_system.h"
#include "driver_timer.h"
#include "driver_pmu.h"
#include "driver_rtc.h"
#include "sys_utils.h"

#include "stdc.h"
#include "share/calendar.h"
#include "mcu.h"
#include "sys_clock.h"

#define LOGTAG "SYS_CLOCK"


struct timer_lvr_t
{
    uint32_t load: 16;
    uint32_t unused: 16;
};

struct timer_cvr_t
{
    uint32_t count: 16;
    uint32_t unused: 16;
};

struct timer_cr_t
{
    uint32_t reserved1: 2;
    uint32_t pselect: 2;
    uint32_t reserved2: 2;
    uint32_t count_mode: 1;
    uint32_t count_enable: 1;
    uint32_t unused: 24;
};

struct timer_icr_t
{
    uint32_t data: 16;
    uint32_t unused: 16;
};

struct timer
{
    struct timer_lvr_t load_value;
    struct timer_cvr_t count_value;
    struct timer_cr_t control;
    struct timer_icr_t interrupt_clear;
};

/**
 * 根据计算定时间隔时间，选择最合适的时钟分频系数
 * 在满足间隔时间的情况下，定时误差尽可能的小，也就是尽可能大的分频
    prescale: 1
    sys_clk         6M      12M     24M     48M
    accuracy        1/6us   1/12us  1/24us  1/48us
    max period      10922us 5461us  2730us  1365us

    prescale: 16
    sys_clk         6M      12M     24M     48M
    accuracy        8/3us   4/3us   2/3us   1/3us
    max period      174.7ms 87.3ms  43.6ms  21.8ms

    prescale: 256
    sys_clk         6M      12M     24M     48M
    accuracy        128/3us 64/3us  32/3us  16/3us
    max period      2796ms  1398ms  699ms   349ms
 */
static const uint32_t _timer_max_period[][TIMER_PRESCALE_MAX] = {
	{0xFFFF*1/48, 0xFFFF*16/48, 0xFFFF*256/48},	// 48M
	{0xFFFF*1/24, 0xFFFF*16/24, 0xFFFF*256/24},	// 24M
	{0xFFFF*1/12, 0xFFFF*16/12, 0xFFFF*256/12},	// 12M
	{0xFFFF*1/6 , 0xFFFF*16/6 , 0xFFFF*256/6 },	// 6M
};


/// 根据计算定时间隔时间(us)，选择最合适的时钟分频系数
/// @param count [in] 定时间隔时间; [out] 定时器计数值
/// @return 定时器分频系数；返回 TIMER_PRESCALE_MAX 表示 count 指定的间隔时间超过了定时器允许的最大定时时间
static enum timer_prescale_t mcu_timer_calc_prescale(uint32_t *count) {
    uint8_t sys_clk_cfg = system_get_pclk_config();
	const uint32_t *divmax;

    if(sys_clk_cfg == 48) {
        divmax = _timer_max_period[0];
    } else if(sys_clk_cfg == 24) {
        divmax = _timer_max_period[1];
    } else if(sys_clk_cfg == 12) {
        divmax = _timer_max_period[2];
    } else if(sys_clk_cfg == 6) {
        divmax = _timer_max_period[3];
    }

    /*  */ if(divmax[TIMER_PRESCALE_256] < *count) {
        return TIMER_PRESCALE_MAX;
    } else if(divmax[TIMER_PRESCALE_16 ] < *count) {
		*count = ((*count) * sys_clk_cfg) >> 8;
        return TIMER_PRESCALE_256;
    } else if(divmax[TIMER_PRESCALE_1  ] < *count) {
		*count = ((*count) * sys_clk_cfg) >> 4;
        return TIMER_PRESCALE_16;
    } else {
		*count = (*count) * sys_clk_cfg;
        return TIMER_PRESCALE_1;
    }
}


//
// 关于“系统滴答定时器”
//
// 系统当前 tick 数高32位
static uint32_t _systick_h32 = 0;

// TIMER0 中断处理
_RAMCODE_ void timer0_isr_ram(void) {
    timer_clear_interrupt(PCB_SYSTICK_TIMER);
	_systick_h32++;
}

void mcu_systick_timer_init() {
    volatile struct timer *timerp = (volatile struct timer *)PCB_SYSTICK_TIMER;
    timerp->control.count_enable = 0;           // 先停止计时
    timerp->control.count_mode = TIMER_FREE_RUN;// 自由运行(永久运行)
    timerp->control.pselect = TIMER_PRESCALE_1; // CPU 主频
    timerp->interrupt_clear.data = 0x01;        // 清除中断标志
	// 设置初始值
    timerp->load_value.load = 0xFFFF; 			// 最大计数(只支持向下计数)
	// 与系统时间同步
	uint8_t pclk = system_get_pclk_config();
	_systick_h32 = (mcu_get_ms() * 1000 * pclk) >> 16;

	// 设置中断优先级并使能中断
    NVIC_EnableIRQ(PCB_SYSTICK_TIMER_IRQn);
	// 开始计时
    timerp->control.count_enable = 1;
}

uint32_t mcu_get_systick(void) {
    volatile struct timer *timerp = (volatile struct timer *)PCB_SYSTICK_TIMER;
	uint16_t _systick_l16 = 0xFFFF - timerp->count_value.count; // 取得向上计数值
	return (_systick_h32 << 16) | _systick_l16;
}

uint32_t mcu_get_us(void) {
    volatile struct timer *timerp = (volatile struct timer *)PCB_SYSTICK_TIMER;
	uint16_t _systick_l16 = 0xFFFF - timerp->count_value.count; // 取得向上计数值
	uint8_t pclk = system_get_pclk_config();
	return ((_systick_h32 << 16) | _systick_l16) * 1L / pclk;
}

uint32_t mcu_elapsed_us(uint32_t old) {
	uint32_t curr = mcu_get_us();
	return curr >= old ? (curr - old) : (0xFFFFFFFF - old + curr);
}

uint32_t mcu_retiming_us(uint32_t *retimer) {
	uint32_t curr = mcu_get_us();
	uint32_t old = *retimer; *retimer = curr;
	return curr >= old ? (curr - old) : (0xFFFFFFFF - old + curr);
}

void mcu_delay_us(uint32_t num) {
	co_delay_10us(IDIV45(num, 10));
}


//
// 关于“毫秒定时器”: 使用系统自带的时钟 system_get_curr_time()
//
uint32_t mcu_get_ms(void) {
	return system_get_curr_time();
}

uint32_t mcu_elapsed_ms(uint32_t old) {
	uint32_t curr = system_get_curr_time();
	return (curr >= old) ? (curr - old) : (MCU_SYSTEM_MS_MAX - old + curr);
}

void mcu_delay_ms(uint32_t num) {
	uint32_t ms = system_get_curr_time();
	while(mcu_elapsed_ms(ms) < num);
}


//
// 关于“微秒定时器”
//
static mcu_ustimer_handler_t _ustimer_handler = NULL;
static void *_ustimer_cookie = NULL;
static uint32_t _ustimer_repeat = 0;

_RAMCODE_ void mcu_ustimer_stop(void) {
	volatile struct timer *timerp = (volatile struct timer *)PCB_US_TIMER;
	timerp->control.count_enable = 0;
	NVIC_DisableIRQ(PCB_US_TIMER_IRQn);
}

std_err_t mcu_ustimer_run_every(uint32_t interval, uint32_t repeat, mcu_ustimer_handler_t handler, void *cookie) {
	if(!interval || !handler) { return STD_ERR_INVALID_ARG; }
	
    // 根据计算定时间隔时间，选择最合适的时钟分频系数
    enum timer_prescale_t prescale = mcu_timer_calc_prescale(&interval);
	if(prescale == TIMER_PRESCALE_MAX) { return STD_ERR_OUT_OF_RANGE; }

	// 保存参数
	_ustimer_handler = handler; _ustimer_cookie = cookie;
	_ustimer_repeat = repeat;
	
	// 定时器地址
    volatile struct timer *timerp = (volatile struct timer *)PCB_US_TIMER;
	// 停止计时
	timerp->control.count_enable = 0;
	// 清除中断标志
    timerp->interrupt_clear.data = 0x01;
	// 重新设置时钟分频
	timerp->control.pselect = prescale;
	
	// 自由运行(永久运行?)
    timerp->control.count_mode = TIMER_FREE_RUN;
    // 设置计数值(只支持向下计数)
    timerp->load_value.load = interval;
	// 开始计时
    timerp->control.count_enable = 1;
	NVIC_EnableIRQ(PCB_US_TIMER_IRQn);
    return STD_ERR_OK;
}

// TIMER0 中断处理
_RAMCODE_ void timer1_isr_ram(void) {
	// 如果不继续了，停止定时器
	if(!_ustimer_handler || !_ustimer_repeat) { mcu_ustimer_stop(); }
	// 回调
	if(_ustimer_handler) { _ustimer_handler(_ustimer_cookie); }
	// 重复次数减一
	if(_ustimer_repeat && _ustimer_repeat != MAXU32) { _ustimer_repeat--; }
	// 清除中断
    timer_clear_interrupt(PCB_US_TIMER);
}

static void mcu_ustimer_test_handler(void *cookie) {
	co_printf("%d ", _ustimer_repeat);
}

void mcu_ustimer_test(uint32_t interval, uint32_t repeat) {
	mcu_ustimer_run_every(interval, repeat, mcu_ustimer_test_handler, NULL);
}


//
// 关于 RTC
//
uint32_t mcu_get_pmu_clk_freq(void) {
    uint8_t cfg = (ool_read(PMU_REG_CLK_CONFIG) & PMU_SYS_CLK_SEL_MSK) >> 6;
    switch(cfg) {
        default:
        case PMU_SYS_CLK_RC:     return 62500;   // 内部 62.5KHz RC 振荡器
        case PMU_SYS_CLK_RC_DIV: return 62500/2; // 内部 62.5KHz RC 振荡器 1/2 分频
        case PMU_SYS_CLK_32768:  return 32768;   // 外部 32768Hz 晶振
        case PMU_SYS_CLK_32K:    return 32000;   // 外部 24M 晶振 32KHz 分频
    }
}

static FUNC_loadBaseTime _rtcLoadBaseTime = NULL;
static FUNC_saveBaseTime _rtcSaveBaseTime = NULL;

// 多长时间保存一次基准时间(s)
#define RTC_UPDATE_INTERVAL 7200

// 读取当前 RTC 计数值并换算成秒数
static uint32_t _get_rtc_count_s(void) {
    // 读取当前 RTC 计数值
	uint32_t count = ool_read32(PMU_REG_RTC_VALUE_0);
    // 根据 RTC 时钟频率换算成秒
    return count / mcu_get_pmu_clk_freq();
}

// 设置 RTC 计数值为指定秒数
static void _set_rtc_count_s(uint32_t count) {
    // 保留当前计数值秒内的余数，以防累计误差
    uint32_t remain = ool_read32(PMU_REG_RTC_VALUE_0) % mcu_get_pmu_clk_freq();
    // 根据 RTC 时钟频率换算成计数值
	count = count * mcu_get_pmu_clk_freq() + remain;
    
    // 1.写入 RTC 计数值到 RTC UPDATE 寄存器
    ool_write32(PMU_REG_RTC_UPDATE_0, count);
    // 2.PMU_REG_RTC_SETTINGS 寄存器 PMU_RTC_UPDATE_EN 位置 1
    ool_write(PMU_REG_RTC_SETTINGS, ool_read(PMU_REG_RTC_SETTINGS) | PMU_RTC_UPDATE_EN);
    // 3.等待2个 PMU 时钟周期
    co_delay_10us(7);
    // 4.PMU_REG_RTC_SETTINGS 寄存器 PMU_RTC_UPDATE_EN 位置 0
    ool_write(PMU_REG_RTC_SETTINGS, ool_read(PMU_REG_RTC_SETTINGS) & (~PMU_RTC_UPDATE_EN));
}

void mcu_rtc_rearm_updater(void) {
	// 检查当前 RTC 计数秒数是否达到计时间隔上限
	uint32_t count = _get_rtc_count_s();
	if(count >= RTC_UPDATE_INTERVAL) {
		// RTC 重新开始计数
		_set_rtc_count_s(0);
		// 保存 RTC 基准时间
		_rtcSaveBaseTime(_rtcLoadBaseTime() + count);
    }
    
	// 设置 Alarm-B 门限值
    ool_write32(PMU_REG_RTC_ALMB_VALUE_0, RTC_UPDATE_INTERVAL * mcu_get_pmu_clk_freq());
    // 使能 Alarm-B 及其中断
    ool_write(PMU_REG_RTC_SETTINGS, ool_read(PMU_REG_RTC_SETTINGS) | PMU_RTC_ALARM_B_EN | PMU_RTC_ALMB_INT_EN | PMU_RTC_ALMB_PO_EN);
    // 使能 PMU 中断
    NVIC_EnableIRQ(PMU_IRQn);
}

uint32_t mcu_get_clock(void) {
    return _rtcLoadBaseTime() + _get_rtc_count_s();
}

void mcu_set_clock(uint32_t timestamp) {
    // RTC 重新开始计数
    _set_rtc_count_s(0);
    // 保存 RTC 基准时间
    _rtcSaveBaseTime(timestamp);
    // 设置 RTC Alarm-B 定时器，以便在 RTC 计数溢出之前进行更新
    mcu_rtc_rearm_updater();
}

/// RTC Alarm 定时中断
_RAMCODE_ void rtc_isr_ram(uint8_t rtc_idx) {
    mcu_rtc_rearm_updater();
}

void mcu_rtc_init(FUNC_loadBaseTime loadBaseTime, FUNC_saveBaseTime saveBaseTime) {
    _rtcLoadBaseTime = loadBaseTime;
    _rtcSaveBaseTime = saveBaseTime;

    // 检查 Flash 中保存的 RTC 基准时间是否已初始化
    if(_rtcLoadBaseTime() == 0xFFFFFFFF || _rtcLoadBaseTime() == 0) {
        logw("Init RTC basetime !\r\n");
        _rtcSaveBaseTime(APP_RTC_INIT_BASETIME);
    }

    // 检查 RTC 是否已初始化
    if(_get_rtc_count_s() == 0) {
        // RTC 未初始化
        logw("Init RTC ...\r\n");
        // 复位 RTC
        ool_write(PMU_REG_RST_CTRL, ool_read(PMU_REG_RST_CTRL) | PMU_RST_RTC);
        // 使能 PMU 的 RTC 时钟
        ool_write(PMU_REG_CLK_CTRL, ool_read(PMU_REG_CLK_CTRL) | PMU_RTC_CLK_EN);
        // 使能 RTC
        ool_write(PMU_REG_RTC_SETTINGS, ool_read(PMU_REG_RTC_SETTINGS) | PMU_RTC_EN);
        // RTC 重新开始计数
        _set_rtc_count_s(0);
    } else {
        // 如果当前 RTC 时间不是初始值，则表示已经初始化过，不能再次初始化！
        logd("RTC continue: %s\r\n", getDateTimeString(mcu_get_clock()));
    }

    // 设置 RTC Alarm-B 定时器，以便在 RTC 计数溢出之前进行更新
    mcu_rtc_rearm_updater();
}

uint32_t mcu_elapsed_second(uint32_t timestamp) {
    uint32_t tm = mcu_get_clock();
	return tm > timestamp ? (tm - timestamp) : (MCU_RTC_COUNT_MAX - timestamp + tm);
}
